/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package it.txt.access.capability.commons.schema;

import it.txt.access.capability.commons.osgi.CapabilityCommonsActivator;
import it.txt.access.capability.commons.schema.factory.CapabilitySchemaSource;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.text.MessageFormat;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSInput;
import org.w3c.dom.ls.LSResourceResolver;

/**
 * 
 * @author seccia
 */
public class CapabilityNamespacesResolver implements LSResourceResolver {

    private static final Logger LOGGER = Logger.getLogger(CapabilityNamespacesResolver.class.getName());
    private Set<CapabilitySchemaSource> streams;
    DOMImplementationLS domImplementationLS;

    public CapabilityNamespacesResolver(Set<CapabilitySchemaSource> streams) {
        this.streams = streams;
        doBootstrap();
    }

    private void doBootstrap() {
        if (LOGGER.isLoggable(Level.FINER))
            LOGGER.finer("Check 1: " + DOMImplementationRegistry.PROPERTY
                + "=" + System.getProperty(DOMImplementationRegistry.PROPERTY));

        System.setProperty(DOMImplementationRegistry.PROPERTY,
                "org.apache.xerces.dom.DOMXSImplementationSourceImpl");

        if (LOGGER.isLoggable(Level.FINER))
            LOGGER.finer("Check 2: " + DOMImplementationRegistry.PROPERTY
                + "=" + System.getProperty(DOMImplementationRegistry.PROPERTY));

        try {
            DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
            if (LOGGER.isLoggable(Level.FINER))
                LOGGER.finer("DOMImplementationRegistry :: CREATED");
            domImplementationLS =
                    (DOMImplementationLS) registry.getDOMImplementation("LS");
            if (LOGGER.isLoggable(Level.FINER))
                LOGGER.finer("DOMImplementationLS :: CREATED");
        }
        catch (Exception e) {
            if (LOGGER.isLoggable(Level.FINER))
                LOGGER.log(Level.FINER, "doBootstrap :: ClassNotFoundException :: {0}", e.getMessage());
            try {
                if (LOGGER.isLoggable(Level.FINER))
                    LOGGER.finer("Using Bundle Bootstrap...");
                bundleBootstrap();
                if (LOGGER.isLoggable(Level.FINER))
                    LOGGER.finer("Bootstrap OK.");
            } catch (Exception e1) {
                LOGGER.log(Level.SEVERE, MessageFormat.format(
                        "doBootstrap :: Exception :: {0}", e1.getMessage()),e);
            }
        }
    }

    /*
     *This method should be called if we are in an OSGi container
     */
    private void bundleBootstrap() throws ClassNotFoundException,
            InstantiationException, IllegalAccessException {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        if(CapabilityCommonsActivator.getContextClassLoader() != null){
            if (LOGGER.isLoggable(Level.FINER))
                LOGGER.finer("Using CapabilityCommonsActivator Class loader...");
            Thread.currentThread().setContextClassLoader(CapabilityCommonsActivator.getContextClassLoader());
        }
        else{
            if (LOGGER.isLoggable(Level.FINER))
                LOGGER.finer("Using CapabilityNamespacesResolver Class loader...");
            Thread.currentThread().setContextClassLoader(CapabilityNamespacesResolver.class.getClassLoader());
        }
        DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
        if (LOGGER.isLoggable(Level.FINER))
            LOGGER.finer("DOMImplementationRegistry :: ON BUNDLE :: CREATED");
        domImplementationLS = (DOMImplementationLS) registry.getDOMImplementation("LS");
        if (LOGGER.isLoggable(Level.FINER))
            LOGGER.finer("DOMImplementationLS :: ON BUNDLE :: CREATED");
        Thread.currentThread().setContextClassLoader(cl);
    }

    public LSInput resolveResource(String type, String namespaceURI,
            String publicId, String systemId, String baseURI) {
        if (LOGGER.isLoggable(Level.FINER))
            LOGGER.log(Level.FINER,"\n****\n" + "Resolving XSD Resource\n"
                + "Namespace URI: " + "{0}" + "\n" + "System ID: "
                + "{1}\n****", new Object[]{namespaceURI, systemId});
        try {
            LSInput ret = domImplementationLS.createLSInput();

            for (CapabilitySchemaSource source : streams) {

                CapabilitySchemaSource schema = (CapabilitySchemaSource) source;

                if (schema.getTargetNamespace().equals(namespaceURI)) {
                    URL url = schema.getTargetURI().toURL();
                    URLConnection uc = url.openConnection();
                    ret.setByteStream(uc.getInputStream());
                    ret.setSystemId(systemId);
                    if (LOGGER.isLoggable(Level.FINER))
                        LOGGER.log(Level.FINER, "Resolved namespace: {0} with resource: {1}",
                            new Object[]{schema.getTargetNamespace(), schema.getTargetURI()});
                    return ret;
                }
            }
        } catch (FileNotFoundException e) {
            LOGGER.log(Level.SEVERE, e.getMessage());
        } catch (IOException e) {
            LOGGER.log(Level.SEVERE, e.getMessage());
        }
        LOGGER.log(Level.SEVERE, "[TXT] No stream found for Namespace URI: {0} "
                + "with system ID: {1}", new Object[]{namespaceURI, systemId});
        return null;
    }
}
